package simtester.server

import groovy.time.TimeCategory
import simtester.server.TestCase;
import simtester.server.TestRun;
import simtester.server.Type;
import java.lang.Object;
import grails.plugins.rest.client.RestBuilder;
import grails.converters.*
import org.codehaus.groovy.grails.web.json.*;

class TestRunController {
    def cloudService
    def testRunService

    def create() {
        if (needsAuth()) { return }

        if (request.method == 'POST') {
            def runArgs
            if (hasKey(params, 'mins-')) {
                runArgs = buildLoadTestAttrs(params)
                cloudService.runLoadTestAgent(runArgs)
            } else {
                runArgs = buildGuiTestAttrs(params)
                cloudService.runTestAgent(runArgs)
            }

            redirect (action: 'running')
        } else {
            def u = User.findByUsername(session.user)
			def catlist = Category.list().collect { it.name }

			params.sort = params.sort ?: 'name'
            
            def testcases
            def testcasescount = u.team.testcases.size()
            if (testcasescount > 0) {
                testcases = u.team.testcases.sort { a,b ->
                    if (params.sort == 'owner') {
                        if (params.order == 'desc') {
                            b.owner.name <=> a.owner.name
                        } else {
                            a.owner.name <=> b.owner.name
                        }
                    } else {
                        if (params.order == 'desc') {
                            b."${params.sort}" <=> a."${params.sort}"
                        } else {
                            a."${params.sort}" <=> b."${params.sort}"
                        }
                    }
                }
    	/*		
    			def testcasescount = u.team.testcases.size()
    			println "params.offset ====> $params.offset"
    			println "params.max =======> $params.max"
    			if (testcasescount != 0) {
    				int offset = 0
    				int max    = 2
    				if (params.offset) {
    					offset = params.offset.toInteger()
    					max    = params.max.toInteger()
    				}
    				
    				int end = offset + max - 1
    				if (end >= testcasescount) {
    					end = testcasescount - 1
    				}
    				println "testcasescount: $testcasescount"
    				println "end: $end"
    				println "offset: $offset"
    				testcases = testcases[offset..end]
    			} else {
    				params.offset = 0
    				params.max = 0
    			}
    			
    		*/	

				int offset = 0
				int max    = 10

				if (params.offset) {
					offset = params.offset.toInteger()
					max    = params.max.toInteger()
				}
				
				int end = offset + max - 1
				if (end >= testcasescount) {
					end = testcasescount - 1
				}
				testcases = testcases[offset..end]
            } else {
                testcases = []
            }
			
			def typelist = Type.list().collect { it.name }

			[testcases: testcases, activeView: 'testcases', catlist: catlist, testcasescount: testcasescount, typelist: typelist]
        }
    }
    
    def running() {
        if (needsAuth()) { return }
        
        def testruns = User.findByUsername(session.user).team.findTestRuns()
		def testrunscount = testruns.size()

        if (testrunscount > 0) {
    		int offset = 0
    		int max    = 10
    
    		if (params.offset) {
    			offset = params.offset.toInteger()
    			max    = params.max.toInteger()
    		}
    		
    		int end = offset + max - 1
    		if (end >= testrunscount) {
    			end = testrunscount - 1
    		}
            
            testruns = testruns[offset..end]
        }
		
        [testruns: testruns, activeView: 'running', testrunscount: testrunscount]
    }
    
    def update() {
        def tr = TestRun.get(params.id.toLong())
        
        if (!tr) {
            render(contentType:'text/json') {
                msg = 'failed'
                error = "cannot find ID ${params.id}"
            }
        } else {
            // If there is at least one iteration that's not completed, then testrun has not finished
            def stillrunning = true
            def counter = 0
            def limit = 10000
            def step = 2000
            while (stillrunning && counter < limit) {
                TestRun.withSession { session ->
                    tr = TestRun.get(params.id.toLong())
                    stillrunning = tr.iterations.any { it.status == 'running' }
                    session.clear()
                }
                println "stillrunning: $stillrunning"
                sleep step
                counter += step
            }

            if (!stillrunning) {
                testRunService.retryTestRunSave {
                    tr = TestRun.get(params.id.toLong())
                    if (tr.status != 'completed') {
                        tr.status = 'completed'
                        tr.endDate = new Date()
                        tr.save(flush: true)
                    }
                }
            }
            render (contentType:'text/json') {
                msg = 'ok'
            }
        }

        cloudService.scheduleRemovalOfInstances(tr)
    }
    
    def sendresults() {
        testRunService.saveTestRunResults(params.id.toLong(), request.JSON.results)

        render (contentType:'text/json') {
            msg = 'ok'
        }
    }
    
    def results() {
        def tr = TestRun.get(params.id.toLong())
        
        boolean isTestCase = false
        if (tr.testcase) {
            isTestCase = true
        }
        
        def testcases = []
        if (isTestCase) {
            testcases << [id: tr.testcase.id, name: tr.testcase.name, users: tr.users]
        } else {
            def usersHash = tr.usersPerTest
            if (usersHash) {
                def ids = usersHash.collect { it.key.toLong() }
                testcases = TestCase.getAll(ids).collect { [id: it.id, name: it.name, users: usersHash[it.id.toString()]] }
            } else {
                testcases = TestCase.getAll(tr.testcaseIds).collect { [id: it.id, name: it.name] }
            }
        }
        
        [testrun: tr, testcases: testcases, isTestCase: isTestCase, activeView: 'running']
    }
    
    def details() {
        def tr = TestRun.get(params.id.toLong())
        
        def results
        if (tr.type == 'GUI') {
            results = ResultEntry.withCriteria {
                eq 'testrun', tr
                eq 'user', params.user.toInteger()
                eq 'iteration', params.num.toInteger()
            }
        } else {
            results = ResultEntry.withCriteria {
                eq 'testrun', tr
                eq 'testcase', params.tc
                eq 'user', params.user.toInteger()
                eq 'iteration', params.num.toInteger()
            }
        }
        [entries: results, activeView: 'running']
    }

    private boolean needsAuth() {
        if (!session.user) {
            redirect (controller: 'user', action: 'index')
            return true
        }
        return false
    }
    
    private buildGuiTestAttrs(params) {
        def runArgs = [testrunName: params.trname]
        
        if (params.testcase) {
            runArgs.testcaseId = params.testcase.toLong()
            if (params.users) {
                runArgs.users = params.users.toInteger()
            }
        } else {
            runArgs.testsuiteId = params.testsuite.toLong()
            def users = params.findAll { it.key =~ /^tc\d+$/ }
            users = users.collectEntries([:]) { k, v ->
                [k.replaceFirst('tc', ''), v.toInteger()]
            }
            runArgs.users = users
        }
        
        if (params.repeat == 'count') {
            runArgs.repeats = params.repeatcount.toInteger()
        } else {
            def duration
            use (TimeCategory) {
                duration = params.hours.toInteger().hours + params.mins.toInteger().minutes + params.secs.toInteger().seconds
            }
            runArgs.duration = duration.toMilliseconds()
        }

        return runArgs
	}
    
    private buildLoadTestAttrs(params) {
        def runArgs = [testrunName: params.trname]
        
        runArgs.testsuiteId = params.testsuite.toLong()
        
        runArgs.testcases = []
        def tcs = params.findAll { it.key.startsWith('mins-') }
        tcs.eachWithIndex { tc, i ->
            runArgs.testcases << [id: tc.key.replaceAll('mins-', '').toLong()]
        }
        
        runArgs.testcases.each { tc ->
            tc.phases = []
            
            // Only 1 phase
            if (params['mins-' + tc.id] instanceof java.lang.String) {
                ['users', 'permin', 'persec', 'hours', 'mins', 'secs'].each {
                    params[it + '-' + tc.id] = [params[it + '-' + tc.id]]
                }
            }
            int numPhases = params['mins-' + tc.id].size()
            numPhases.times { i ->
                tc.phases[i] = [users: params['users-' + tc.id][i].toInteger()]
                tc.phases[i].per = 1000 *
                    (params['permin-' + tc.id][i].toInteger() * 60 +
                     params['persec-' + tc.id][i].toInteger())

                tc.phases[i].duration = 1000 *
                    (params['hours-' + tc.id][i].toInteger() * 3600 +
                     params['mins-' + tc.id][i].toInteger() * 60 +
                     params['secs-' + tc.id][i].toInteger())
            }
        }
        
        return runArgs
    }
    
    def addbugreport() {
        def summarytxt = params.sumtxt
        def prioritysel = params.priority
        def descriptiontxt = params.desctxt
        def rest = new RestBuilder()
        def resp = rest.post("https://cmpe295b.atlassian.net/rest/api/2/issue/"){
            auth 'simuser', 'simuser'
            contentType "application/json"
            json {
                fields = [  project : [ key : 'SIM' ],
                            summary : summarytxt,
                            priority : [ id : prioritysel ],
                            description : descriptiontxt,
                            issuetype : [ name : 'Bug' ]
                          ]
            }
        }

        def resultString = new String( resp.body )
        def resultJSON = JSON.parse(resultString)
        def resultStatus = resp.status
                    
        if ( resultStatus == 201 ) {
            render 'success'
        } else {
            render (contentType: 'text/json') {
                [result : resultJSON]
            }
        }
    }
    
    private boolean hasKey(map, str) {
        boolean match = false
        map.each {
            if (it.key.contains(str)) {
                match = true
            }
        }
        return match
    }
}
